package ualrcdg.server;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.w3c.dom.Document;

import ualrcdg.shared.CDGXMLHelper;
import ualrcdg.shared.exceptions.CDGException;
import ualrcdg.shared.exceptions.CDGParseException;
import ualrcdg.shared.requests.AuthenticatePlayerRequest;
import ualrcdg.shared.requests.RegisterPlayerRequest;
import ualrcdg.shared.requests.UpdateProgressRequest;
import ualrcdg.shared.requests.ValidateRuleRequest;
import ualrcdg.shared.responses.AuthenticatePlayerResponse;
import ualrcdg.shared.responses.RegisterPlayerResponse;
import ualrcdg.shared.responses.UpdateProgressResponse;
import ualrcdg.shared.responses.ValidateRuleResponse;

/**
 * Responsible for all aspects of the CDG Server application that do not deal explicitly with file management or communication with the CDG Clients.
 * These duties include registration and authentication of Players, validation of Player progress (when requested by the Client application), and logging of Player progress.
 */
public class GameServer
{
	private final RuleValidator validator;

	private final PlayerRegistrar registrar;
	
	private final ProgressLogger logger; 
	
	/**
	 * Primary constructor
	 * 
	 * @param rootFolder the name of the folder (relative to the current working directory) that contains all files and folders necessary for the CDG Server application
	 * @param logFolder the name of the folder (relative to the rootFolder) that contains any existing (and will contain any newly created) game logs
	 * @param validatorListing the name of the file (within the rootFolder) that describes the currently-implemented rule validators
	 * @param playerListing the name of the file (within the rootFolder) that contains the serialized descriptions of all registered players
	 * @throws IOException If an IO error occurs during initialization
	 * @throws ClassNotFoundException If the class files for one or more of the rule validators described in the validatorListing file cannot be located
	 * @throws CDGException If one or more of the listed rule validators cannot be registered with the RuleValidator, or if one or more of the serialized Player objects cannot be re-registered upon initialization
	 */
	public GameServer( String rootFolder, String logFolder, String validatorListing, String playerListing ) throws IOException, ClassNotFoundException, CDGException
	{
		System.out.println( "GameServer(" + rootFolder + ", " + logFolder + ", " + validatorListing + ", " + playerListing + ")" );
		String rootPath = rootFolder + File.separator;
		
		try
		{
			validator = new RuleValidator( rootPath, validatorListing );
		}
		catch( CDGException | IOException e )
		{
			throw e;
		}

		try
		{
			registrar = new PlayerRegistrar( rootPath, playerListing );
		}
		catch( CDGException | IOException e )
		{
			throw e;
		}

		logger = new ProgressLogger( rootFolder, logFolder );
	}
	
	/**
	 * Forwards a registerPlayer request to the associated PlayerRegistrar member
	 * 
	 * @param request the XML request document containing the registration information to be added to the player database
	 * @return an XML response document that indicates whether or not the player registration was successful
	 * @throws CDGParseException If the XML request document could not be parsed
	 * 
	 *  @see PlayerRegistrar
	 */
	Document registerPlayer( Document request ) throws CDGParseException
	{
		RegisterPlayerRequest req = CDGXMLHelper.parseRegisterPlayerRequestDocument( request );
		
		boolean response = registrar.registerPlayer( req );
		return CDGXMLHelper.createRegisterPlayerResponseDocument( new RegisterPlayerResponse( req.requestId, response ) );
	}
	
	/**
	 * Forwards a authenticatePlayer request to the associated PlayerRegistrar member
	 * 
	 * @param request the XML request document containing the authentication information to be verified against the player database
	 * @return an XML response document that indicates whether or not the player authentication was successful
	 * @throws CDGParseException If the XML request document could not be parsed
	 */
	Document authenticatePlayer( Document request ) throws CDGParseException
	{
		AuthenticatePlayerRequest req = CDGXMLHelper.parseAuthenticatePlayerRequestDocument( request );
		
		boolean response = registrar.authenticatePlayer( req );
		return CDGXMLHelper.createAuthenticatePlayerResponseDocument( new AuthenticatePlayerResponse( req.requestId, response ) );
	}
	
	/**
	 * Forwards a validateRule request to the associated RuleValidator member
	 * 
	 * @param request the XML request document containing all information necessary to attempt to validate that a rule has been completed
	 * @return an XML response document that indicates whether or not the rule validation was successful
	 * @throws CDGParseException If the XML request document could not be parsed
	 */
	Document validateRule( Document request ) throws CDGParseException, IOException
	{
		ValidateRuleRequest req = CDGXMLHelper.parseValidateRuleRequestDocument( request );
		
		boolean response = validator.validateRule( req );
		return CDGXMLHelper.createValidateRuleResponseDocument( new ValidateRuleResponse( req.requestId, response ) );
	}
	
	/**
	 * Forwards a logProgress request to the associated ProgressLogger member
	 * 
	 * @param request the XML request document containing all information necessary to attempt to log a unit of progress
	 * @return an XML response document that indicates whether or not the progress logging was successful
	 * @throws CDGParseException If the XML request document could not be parsed
	 */
	Document logProgress( Document request ) throws CDGParseException
	{
		UpdateProgressRequest req = CDGXMLHelper.parseUpdateProgressRequestDocument( request );
		
		boolean response = logger.logProgress( req );
		return CDGXMLHelper.createUpdateProgressResponseDocument( new UpdateProgressResponse( req.requestId, response ) );
	}
	
	/**
	 * Commits the registered players to the filename provided to the PlayerRegistrar's constructor
	 * 
	 * @throws FileNotFoundException If the file to which the Player database will be written cannot be found
	 * @throws IOException If an IO error occurs while committing the Player database to a file
	 */
	public void commitPlayers( ) throws FileNotFoundException, IOException
	{
		registrar.commit( );
	}
	
	/**
	 * Registers a rule validation implementation with the RuleValidator member of this GameServer instance
	 * 
	 * @param ruleType type of rule that this implementation will validate
	 * @param validatorClassName name of the rule validation implementation class
	 * @throws CDGException If a validator is already registered for the given ruleType
	 */
	public void registerValidator( String ruleType, String validatorClassName ) throws CDGException
	{
		validator.registerValidator( ruleType, validatorClassName );
	}
	
	/**
	 * Commits the registered rule validators to the filename provided to the RuleValidator's constructor
	 * 
	 * @throws FileNotFoundException If the file to which the rule validators will be written cannot be found
	 */
	public void commitValidators( ) throws FileNotFoundException
	{
		validator.commit( );
	}
}